package com.lhs.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.lhs.Result.Result;
import com.lhs.config.redis.RedisKeyConstants;
import com.lhs.config.redis.ZiDeRedisUtil;
import com.lhs.entity.blog.blog_like;
import com.lhs.service.HotBlogService;
import com.lhs.service.blog_likeService;
import com.lhs.mapper.blog_likeMapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* @author 15977
* @description 针对表【blog_like(点赞记录表)】的数据库操作Service实现
* @createDate 2025-09-11 09:04:15
*/
@Slf4j
@Service
public class blog_likeServiceImpl extends ServiceImpl<blog_likeMapper, blog_like>
    implements blog_likeService{


    @Autowired
    private ZiDeRedisUtil ziDeRedisUtil;
    @Autowired
    private RedissonClient redissonClient; // 注入Redisson客户端
    @Autowired
    private blog_likeMapper blogLikeMapper;

    @Autowired
    private HotBlogService  hotBlogService;
    @Autowired
    private com.lhs.mapper.blog_post_0Mapper   blogPost0Mapper;


    /**
     * 点赞或取消点赞
     * 采用Redisson分布式锁保证并发安全[8](@ref)
     */
    @Override
    public Result likeBlog(Long postId, Long userId) {
        if (postId == null || userId == null) {
            return Result.error("参数错误");
        }

        // 1. 防刷检查：使用Redis记录用户操作时间，5秒内不允许重复点赞同一文章
        String rateLimitKey = String.format(RedisKeyConstants.USER_LIKE_RATE_LIMIT, userId, postId);
        Boolean canLike = ziDeRedisUtil.setIfAbsent(rateLimitKey, "1", 5, TimeUnit.SECONDS);
        if (Boolean.FALSE.equals(canLike)) {
            return Result.error("操作过于频繁，请稍后再试");
        }

        // 2. 获取分布式锁，锁定对该文章的操作[8](@ref)
        String lockKey = String.format(RedisKeyConstants.LOCK_BLOG_LIKE, postId);
        RLock lock = redissonClient.getLock(lockKey);

        try {
            // 尝试加锁，等待时间2秒，锁持有时间5秒防止死锁
            if (lock.tryLock(2, 5, TimeUnit.SECONDS)) {
                // 检查用户是否已点赞
                String likedUsersKey = String.format(RedisKeyConstants.BLOG_LIKED_USERS, postId);
                String likeCountKey = String.format(RedisKeyConstants.BLOG_LIKE_COUNT, postId);
                String userLikedBlogsKey = String.format(RedisKeyConstants.USER_LIKED_BLOGS, userId);

                boolean isLiked = ziDeRedisUtil.isMemberOfSet(likedUsersKey, userId.toString());

                if (isLiked) {
                    // 取消点赞
                    ziDeRedisUtil.removeFromSet(likedUsersKey, userId.toString());
                    ziDeRedisUtil.decrement(likeCountKey, 1L);
                    ziDeRedisUtil.removeFromSet(userLikedBlogsKey, postId.toString());
                    log.info("用户{}取消点赞文章{}", userId, postId);
                } else {
                    // 点赞
                    ziDeRedisUtil.addToSet(likedUsersKey, userId.toString());
                    ziDeRedisUtil.increment(likeCountKey, 1L);
                    ziDeRedisUtil.addToSet(userLikedBlogsKey, postId.toString());
                    log.info("用户{}点赞文章{}", userId, postId);
                }

                // 3. 异步更新数据库[1](@ref)
                asyncUpdateLikeToDatabase(postId, userId, isLiked);

                // 4. 判断文章是否为热点，更新热点文章列表
                hotBlogService.checkAndUpdateHotBlog(postId);

                return Result.success(isLiked ? "取消点赞成功" : "点赞成功");
            } else {
                log.warn("获取点赞锁失败，postId: {}, userId: {}", postId, userId);
                return Result.error("系统繁忙，请重试");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("点赞操作被中断", e);
            return Result.error("操作失败");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 异步更新数据库[1](@ref)
     */
    @Async
    public void asyncUpdateLikeToDatabase(Long postId, Long userId, boolean isLiked) {
        try {
            // 使用Redisson锁保证数据库操作安全
            String dbLockKey = "lock:db:blog:like:" + postId + ":" + userId;
            RLock dbLock = redissonClient.getFairLock(dbLockKey); // 使用公平锁

            try {
                if (dbLock.tryLock(3, 10, TimeUnit.SECONDS)) {
                    if (isLiked) {
                        // 删除点赞记录
                        blogLikeMapper.deleteLike(postId, userId);
                        blogPost0Mapper.decrementLikeCount(postId);
                    } else {
                        // 插入点赞记录
                        blog_like blogLike = new blog_like();
                        blogLike.setPostId(postId);
                        blogLike.setUserId(userId);
                        blogLike.setCreateTime(new Date());
                        blogLikeMapper.insert(blogLike);
                        blogPost0Mapper.incrementLikeCount(postId);
                    }
                }
            } finally {
                if (dbLock.isHeldByCurrentThread()) {
                    dbLock.unlock();
                }
            }
        } catch (Exception e) {
            log.error("异步更新点赞数据库失败，postId: {}, userId: {}", postId, userId, e);
            // 可以将失败任务放入重试队列
        }
    }

    /**
     * 获取文章点赞数和点赞状态
     */
    @Override
    public Map<String, Object> getBlogLikeInfo(Long postId, Long userId) {
        String likedUsersKey = String.format(RedisKeyConstants.BLOG_LIKED_USERS, postId);
        String likeCountKey = String.format(RedisKeyConstants.BLOG_LIKE_COUNT, postId);

        Map<String, Object> result = new HashMap<>();

        // 获取点赞数
        Long likeCount = ziDeRedisUtil.getCacheObject(likeCountKey);
        if (likeCount == null) {
            // 缓存未命中，从数据库加载并写入缓存
            likeCount = blogLikeMapper.selectLikeCountByPostId(postId);
            ziDeRedisUtil.setCacheObject(likeCountKey, likeCount, 1, TimeUnit.DAYS); // 设置过期时间
        }
        result.put("likeCount", likeCount);

        // 获取用户是否点赞
        if (userId != null) {
            boolean isLiked = ziDeRedisUtil.isMemberOfSet(likedUsersKey, userId.toString());
            result.put("isLiked", isLiked);
        }

        return result;
    }



}




